package com.black.utils.encrypt.sm3;

import com.black.utils.converter.ByteConverter;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Arrays;

/**
 * SM3 摘要
 * 获取的摘要主要用于数字签名的生成和验签
 */
@Slf4j
public class SM3Util {
    private static final String ENCODING = "UTF-8";

    // 添加Bouncy Castle作为安全提供者
    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 对字符串进行 SM3 哈希计算，并返回十六进制字符串表示的结果
     *
     * @param paramStr 待计算哈希的字符串
     * @return 十六进制字符串表示的哈希结果
     */
    public static String digest(String paramStr) {
        //将返回的hash值转换为16进制字符串
        String resultHexString = "";
        try {
            //将字符串转换成byte数组
            byte[] srcData = paramStr.getBytes(ENCODING);
            byte[] resultHash = hash(srcData);
            //将返回的hash值转换成16进制字符串
            resultHexString = ByteConverter.bytesToHexString(resultHash);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        return resultHexString;
    }

    /**
     * 计算给定数据的 SM3 哈希值
     *
     * @param srcData 待计算哈希的数据
     * @return 哈希值的字节数组
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 使用 HMAC-SM3 算法计算给定密钥和数据的哈希值
     *
     * @param key     HMAC 密钥
     * @param srcData 待计算哈希的数据
     * @return HMAC-SM3 哈希值的字节数组
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }

    /**
     * 验证给定字符串经 SM3 哈希后的结果与指定的 SM3 哈希字符串是否一致
     *
     * @param srcStr       原始字符串
     * @param sm3HexString 十六进制字符串表示的 SM3 哈希值
     * @return 若一致返回 true，否则返回 false
     */
    public static boolean verify(String srcStr, String sm3HexString) {
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteConverter.hexStringToBytes(sm3HexString);
            byte[] newHash = hash(srcData);
            return Arrays.equals(sm3Hash, newHash);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage());
        }
        return false;
    }
}
